﻿package com.xmap {
	import flash.display.BitmapData;
	import flash.display.Bitmap;
	import flash.display.Loader;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.net.URLRequest;
	
	public class Emap extends Sprite {
		public var tiles:Array = new Array();
		public var complete:Boolean = false;
		public var offset:int = 0;
		private var tileData:BitmapData;
		private var bitLoader:Loader;
		private var level:Array;
		private var scrollSpeed:int = 2, visibleX:int = 35, visibleY:int = 25, mapWidth:int, mapHeight:int, 
					tileW:int = 16, tileH:int = 16, majorX:Number = 0, i:int, j:int, previ:int, prevj:int,
					dir:int;
		
		//Initalizer, sets up the class.
		public function Emap(level:Array):void {
			//Set level.
			this.level = level;
			
			//Set width and height.
			mapWidth = level[0].length;
			mapHeight = level.length;
			
			//Fetch tiles.
			this.fetchTiles('resources/tiles.png');
		}
		
		//Used to fetch the tiles image file and then being drawing of the map.
		private function fetchTiles(location:String):void {
			//Create a instance of a loader.
			this.bitLoader = new Loader();
			
			//Set listener.
			this.bitLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, tilesLoaded);
			
			//Load tiles.
			this.bitLoader.load(new URLRequest(location));
		}
		
		//Event trigered when the loading of the tiles file is complete.
		private function tilesLoaded(e:Event):void {
			//Set bitmap data.
			this.tileData = Bitmap(this.bitLoader.content).bitmapData;
				
			//Draw map.
			this.drawMap();
		}
		
		//Draws the map to the screen.
		private function drawMap():void {
			//Set tile to create into.
			var tile:Etile;
			
			//Create a map with level array, loop through y.
			for(this.i = 0; this.i < this.visibleY; this.i++) {
				//Create a map with level array, loop through x, create a buffer one to theside.
				for(this.j = 0 ; this.j < (this.visibleX + 1); this.j++) {
					//Create a new tile.
					tile = new Etile(level[this.i][this.j], this.tileData);
					
					//Set tile's position.
					tile.x = this.j * this.tileW;
					tile.y = this.i * this.tileH;
					
					//Set the tile to walkable or not.
					tile.walkable = (this.level[this.i][this.j] == 0)? true : false;
					
					//Add the tile.
					addChild(tile);
					
					//Update the tile's position.
					tile.updatePosition(this.offset);
					
					//Add tile to tiles array.
					this.tiles['i' + this.i + 'j' + this.j] = tile;
				}
			}
			
			//Set map creation to complete.
			this.complete = true;
		}
		
		//Scrolls the map either left or right.
		public function scrollMap(dir:int):void {
			//Make a new tile for adding.
			var tile:Etile;
			
			//If direction is right.
			if(! dir && j <= mapWidth) {
				//Move the map along.
				this.x -= this.scrollSpeed;
				
				//Add offset.
				this.offset += this.scrollSpeed;
				
				//Add distance to majorX.
				this.majorX += this.scrollSpeed;
				
				//If a new tile should be added.
				if (this.majorX >= this.tileW) {
					//Add the extra tile.
					for (this.previ = (this.i - this.visibleY); this.previ < this.i; this.previ++) {
						//Add the rows.
						for(this.prevj = this.j; this.prevj < (this.j + 1); this.prevj++) {
							//Create a new tile.
							tile = new Etile(this.level[this.previ][this.prevj], this.tileData);					
							
							//Set tile's position.
							tile.x = this.prevj * this.tileW;
							tile.y = this.previ * this.tileH;
							
							//Set the tile to walkable or not.
							tile.walkable = (this.level[this.previ][this.prevj] == 0)? true : false;
							
							//Add the tile.
							addChild(tile);
							
							//Add tile to tiles array.
							this.tiles['i' + this.previ + 'j' + this.prevj] = tile;
						}
					}
					
					//Add the extra tile.
					this.j++;
					
					//Remove the unseen tiles.
					this.removeCol(this.j - this.visibleX - 2);
					
					//Take away the tile.
					this.majorX -= this.tileW;
				}
			}
			
			//If direction is left.
			if(dir && (this.j - this.visibleX) > 0) {
				//Move the map along.
				this.x += this.scrollSpeed;
				
				//Add offset.
				this.offset -= this.scrollSpeed;
				
				//Decrease major x.
				this.majorX -= this.scrollSpeed;
				
				//If we must add an extra tile.
				if(this.majorX <= 0) {
					//Take away a tile.
					this.j--;
					
					//Add extra tile.
					for(this.previ = (this.i - this.visibleY); this.previ < this.i; this.previ++) {
						for(this.prevj = (this.j - this.visibleX - 1); this.prevj < (this.j - this.visibleX); this.prevj++) {
							//Create a new tile.
							tile = new Etile(this.level[this.previ][this.prevj], this.tileData);					
							
							//Set tile's position.
							tile.x = this.prevj * this.tileW;
							tile.y = this.previ * this.tileH;
							
							//Set the tile to walkable or not.
							tile.walkable = (this.level[this.previ][this.prevj] == 0) ? true : false;
							
							//Add the tile.
							addChild(tile);
							
							//Add tile to tiles array.
							this.tiles['i' + this.previ + 'j' + this.prevj] = tile;
						}
					}
					
					//Remove unseen tiles.
					this.removeCol(this.j);
					
					//Reset majorX.
					this.majorX += this.tileW;
				}
			}
		}
		
		//Removes a column of tiles from the map.
		private function removeCol(col:int):Boolean {
			//Test if tile exists.	
			if (! (this.tiles['i' + i + 'j' + col])) return false;
			
			//Loop through, removing the column.
			for (var i:int = 0; i < visibleY; i++) {
				//Remove the tile.
				this.removeChild(this.tiles['i' + i + 'j' + col]);
				
				//Remove the tile from the array.
				this.tiles.splice(this.tiles.indexOf(this.tiles['i' + i + 'j' + col]));
			}
			
			//True.
			return true;
		}
		
		//Returns an array of tiles that cannot be walked on so must be 'test'ed for colliding.
		public function testTiles(charX, charY):Array {
			//Set the array.
			var toTest:Array = new Array();
			
			//Loop through tiles.
			for (var k:int = (charY - 5); k < (charY + 5); k++) {
				//Loop through each row.
				for (var l:int = (charX - 5); l < (charX + 5); l++) {
					//Check that the tile exists.
					try {
						//Check if the tile is walkable.
						if (! this.tiles['i' + k + 'j' + l].walkable) {
							//Add to testing array.
							toTest.push(this.tiles['i' + k + 'j' + l]);
						}
					} catch (e:Error) {
						//Catch the error here.
					}
				}
			}
			
			//Return the tiles to test.
			return toTest;
		}
	}
}